import { _decorator, Component, Node, EventTouch, Button } from "cc";
import { Card } from "./Card";
import { Deck } from "./Deck";
import { Player } from "./Player";
import { PlayerActionType } from "./Action";
import { NakamaManager } from "./NakamaManager";
import { PlayerManager } from "./PlayerManager";
import { Match, MatchData, MatchPresenceEvent } from "@heroiclabs/nakama-js";

const { ccclass, property } = _decorator;

const OpCodes = {
  syncGameReq: 9, // 同步游戏状态
  syncGameResp: 109, // 同步游戏状态响应

  seatDown: 10, // 玩家入座
  onSeatedDown: 110, // 有玩家入坐

  seatUp: 11,
  onSeatedUp: 111,

  startGame: 12, // 开始游戏
  onStartedGame: 112, // 游戏准备就绪

  onGamePreFlop: 209, // 游戏已开始
};

const Stage = {
  waitting: "waiting", // 同步游戏状态
  ready: "ready", // 准备
  dealing: "dealing", // 发手牌
  preflop: "pre_flop",
};

@ccclass("PokerManager")
export class PokerManager extends Component {
  private deck: Deck = new Deck(); // 牌堆实例
  private players: Map<string, Player> = new Map<string, Player>(); // 玩家列表
  private seatedPlayers: Map<number, Player> = new Map<number, Player>(); // 玩家列表
  private communityCard: Card[] = []; // 公共牌
  private currentBet: number = 0; // 当前下注金额
  private currentPlayerIndex: number = 0; // 当前行动玩家索引
  private dealerPos: number = 0;

  private match: Match = null; // 当前匹配实例

  private selfSeat: number = -1; // 自己的座位号

  private isCreator: boolean = false; // 是否是房主

  private stage: string = Stage.waitting;

  @property([Node])
  playerNodeList: Node[] = [];

  @property(Button)
  startGameButton: Button = null; // 开始游戏按钮

  private nakama = NakamaManager.getInstance();

  onLoad() {
    this.stage = Stage.waitting;

    this.match = this.nakama.match;

    this.nakama.socket.onmatchdata = (matchData) =>
      this.onReceiveMatchState(matchData);

    this.nakama.socket.onmatchpresence = (matchPresence) =>
      this.onReceivePresence(matchPresence);
  }

  start() {
    this.playerNodeList.forEach((node, index) => {
      node.on(
        Node.EventType.TOUCH_END,
        (event: EventTouch) => {
          this.onSeatDownClick(index, node);
        },
        this
      );
    });

    this.startGameButton.node.on(
      Button.EventType.CLICK,
      this.onStartGameClick,
      this
    );

    this.startSyncGame();
  }

  // 同步游戏
  startSyncGame() {
    this.nakama.socket.sendMatchState(
      this.match.match_id,
      OpCodes.syncGameReq,
      ""
    );
  }

  // 接收游戏消息
  onReceiveMatchState(matchData: MatchData) {
    const data = JSON.parse(new TextDecoder().decode(matchData.data));
    console.log("Received opcode:%o match data:%o", matchData.op_code, data);
    switch (matchData.op_code) {
      case OpCodes.syncGameResp:
        this.onSyncGame(data);
        break;
      case OpCodes.onStartedGame:
        this.onGameReady();
        break;
      case OpCodes.onSeatedDown:
        this.onPlayerDidJoinSeat(data);
        break;
      case OpCodes.onGamePreFlop:
        this.onGamePreFlop(data);
        break;
      default:
        break;
    }
  }

  // 接收玩家入座或离座消息
  onReceivePresence(matchPresence: MatchPresenceEvent) {
    console.log("Received match presence:", matchPresence);
    if (matchPresence.joins) {
      matchPresence.joins.forEach((presence) => {
        const uid = presence.user_id;
        const player = new Player(uid, presence.username);
        this.players.set(uid, player);
      });
    }
  }

  // 同步游戏状态
  onSyncGame(data: any) {
    this.stage = data.stage;
    this.dealerPos = data.dealerPos;

    // 所有玩家同步
    if (data.players) {
      this.players = new Map<string, Player>(Object.entries(data.players));
      console.log("players:", this.players);

      this.players.forEach((player, uid, map) => {
        if (player.seated) {
          this.seatedPlayers.set(player.seat, player);
        }
      });
    }

    // 房主同步
    this.isCreator = data.creatorId === this.nakama.session.user_id;
    if (data.stage === Stage.waitting) {
      this.startGameButton.node.active = this.isCreator; // 只有房主可以看到开始游戏按钮
    }

    // 重置座位
    this.resetSeat();
  }

  // 有玩家入座
  onPlayerDidJoinSeat(data: any) {
    const seat = data.seat;
    const uid = data.uid;
    const chips = data.chips;
    const player = this.players.get(uid);
    if (!player) {
      console.log("没有找到玩家uid:%s", uid);
      return;
    }

    if (uid === this.nakama.session.user_id) {
      // 如果是自己入座，需要转换座位
      if (player.seated) {
        this.seatedPlayers.delete(player.seat);
      }
      this.selfSeat = seat;
      player.seated = true;
      player.seat = seat;
      player.chips = chips;
      this.seatedPlayers.set(player.seat, player);
      this.resetSeat();
      return;
    }

    if (player.seated) {
      this.seatedPlayers.delete(player.seat);
      const lastPlayerNode =
        this.playerNodeList[this.getPlayerIndex(player.seat)];
      lastPlayerNode.getComponent(PlayerManager).showEmptySeat();
    }

    player.seated = true;
    player.seat = seat;
    player.chips = chips;
    this.seatedPlayers.set(player.seat, player);
    const index = this.getPlayerIndex(seat);
    const playerNode = this.playerNodeList[index];
    playerNode.getComponent(PlayerManager).showUserInfo(player, false, index);
  }

  onGameReady() {
    this.stage = Stage.ready;
    this.startGameButton.node.active = false;
    console.log("房主点击已经开始游戏，进入ready阶段");
  }

  onDealHoleCards(data: any) {
    this.stage = Stage.dealing;
    const cards = data.cards as number[];
    const card1 = new Card(cards[0]);
    const card2 = new Card(cards[1]);
    const mine = this.players.get(this.nakama.session.user_id);
    mine.recieveCard(card1);
    mine.recieveCard(card2);
    console.log(
      "收到手牌:%s %s data:%o",
      card1.toString(),
      card2.toString(),
      data
    );
  }

  onGamePreFlop(data: any) {
    this.stage = Stage.preflop;
    console.log("preflop:", data);

    type PlayerData = {
      seated: boolean;
      seat: number;
      chips: number;
      bet: number;
      action: number;
      status: number;
    };

    Object.entries(data.seatedPlayer).forEach(
      ([key, playerData]: [string, PlayerData]) => {
        const player = this.seatedPlayers.get(playerData.seat);
        player.chips = playerData.chips;
        player.bet = playerData.bet;
        player.action = playerData.action;
        // TODO: - status
      }
    );

    this.resetSeat();

    // const mine = this.players.get(this.nakama.session.user_id);
    // const node = this.playerNodeList[this.getPlayerIndex(mine.seat)];
    // const playerManager = node.getComponent(PlayerManager);
    // playerManager.showCards(mine.hand);
  }

  // 玩家点击入座
  onSeatDownClick(index: number, node: Node) {
    const seat = this.getPlayerSeat(index);
    if (this.seatedPlayers.has(seat)) {
      // 如果座位已被占用
      return;
    }

    const match_id = this.nakama.match.match_id;
    const data = JSON.stringify({ seat: seat });
    try {
      this.nakama.socket.sendMatchState(match_id, OpCodes.seatDown, data);
    } catch (err) {
      console.error(err);
    }
  }

  // 房主点击开始游戏按钮
  onStartGameClick() {
    const match_id = this.nakama.match.match_id;
    try {
      this.nakama.socket.sendMatchState(match_id, OpCodes.startGame, "");
    } catch (err) {
      console.error(err);
    }
  }

  // 重置座位
  resetSeat() {
    this.playerNodeList.forEach((node, index) => {
      const playerManager = node.getComponent(PlayerManager);
      playerManager.showEmptySeat();
    });

    this.seatedPlayers.forEach((player, seat, map) => {
      var index = this.getPlayerIndex(seat);
      const playerNode = this.playerNodeList[index];
      const isDealer = this.isGameActive() && seat == this.dealerPos;
      playerNode
        .getComponent(PlayerManager)
        .showUserInfo(player, isDealer, index);
    });
  }

  // 获取当前座位对应的node index
  getPlayerIndex(seat: number): number {
    if (this.selfSeat == -1) {
      return seat; // 如果自己没有入座，直接返回座位号
    }
    var index = seat - this.selfSeat;
    if (index < 0) {
      index = index + this.playerNodeList.length;
    }
    return index;
  }

  // 获取当前index对应的座位号
  getPlayerSeat(index: number): number {
    if (this.selfSeat == -1) {
      return index; // 如果自己没有入座，直接返回座位号
    }
    let seat = (index + this.selfSeat) % this.playerNodeList.length;
    return seat;
  }

  isGameActive(): boolean {
    return this.stage != Stage.waitting && this.stage != Stage.ready;
  }

  // onLoad(){
  //     this.initGame();
  // }

  // initGame() {
  //     this.deck.reset();
  //     this.communityCards = [];
  //     this.players = [
  //         new Player(1, 'Alice'),
  //         new Player(2, 'Bob'),
  //     ]

  //     // 玩家发手牌
  //     this.players.forEach(player => {
  //        player.reset();
  //        player.recieveCard(this.deck.drawCard());
  //        player.recieveCard(this.deck.drawCard());
  //     });

  //     // Flop
  //     this.communityCards.push(this.deck.drawCard());
  //     this.communityCards.push(this.deck.drawCard());
  //     this.communityCards.push(this.deck.drawCard());

  //     // Turn
  //     this.communityCards.push(this.deck.drawCard());

  //     // River
  //     this.communityCards.push(this.deck.drawCard());

  // }

  // handlePlayerAction(player: Player, action: PlayerActionType, amount: number = 0) {
  //     switch (action) {
  //         case PlayerActionType.Fold:
  //             player.folded = true;
  //             console.log(`${player.name} has folded.`);
  //             break;
  //         case PlayerActionType.Check:
  //             if (player.bet === this.currentBet) {
  //                 console.log(`${player.name} checks.`);
  //             } else {
  //                 console.log(`${player.name} cannot check, current bet is ${this.currentBet}.`);
  //             }
  //             break;
  //         case PlayerActionType.Call:
  //             const callAmount = this.currentBet - player.bet;
  //             if (player.chips >= callAmount) {
  //                 player.chips -= callAmount;
  //                 player.bet += callAmount;
  //                 console.log(`${player.name} calls ${callAmount}.`);
  //             } else {
  //                 console.log(`${player.name} does not have enough chips to call.`);
  //             }
  //             break;
  //         case PlayerActionType.Bet:
  //             if (amount > 0 && player.chips >= amount) {
  //                 player.chips -= amount;
  //                 player.bet = amount;
  //                 this.currentBet = amount; // 更新当前下注金额
  //                 console.log(`${player.name} bets ${amount}.`);
  //             } else {
  //                 console.log(`${player.name} does not have enough chips to bet ${amount}.`);
  //             }
  //             break;
  //         case PlayerActionType.Raise:
  //             const raiseAmount = amount;
  //             const totalBet = this.currentBet + raiseAmount;
  //             if (player.chips >= totalBet - player.bet) {
  //                 player.chips -= (totalBet - player.bet);
  //                 player.bet = totalBet;
  //                 this.currentBet = totalBet; // 更新当前下注金额
  //                 console.log(`${player.name} raises to ${totalBet}.`);
  //             } else {
  //                 console.log(`${player.name} does not have enough chips to raise to ${totalBet}.`);
  //             }
  //             break;
  //         case PlayerActionType.AllIn:
  //             const allInAmount = player.chips;
  //             player.bet += allInAmount;
  //             player.chips = 0;
  //             player.allIn = true;
  //             if (player.bet > this.currentBet) {
  //                 this.currentBet = player.bet; // 更新当前下注金额
  //             }
  //             console.log(`${player.name} goes all-in with ${allInAmount}.`);
  //             break;
  //     }
  //     this.nextPlayer();
  // }

  // nextPlayer() {
  //     const max = this.players.length;
  //     for (let i = 0; i < max; i++) {
  //         const idx = (this.currentPlayerIndex + i) % max;
  //         if (this.players[idx].canAct()) {
  //             this.currentPlayerIndex = idx;
  //             console.log(`It's now ${this.players[idx].name}'s turn.`);
  //             return
  //         }
  //     }
  //     console.log("All players have acted or folded.");
  // }
}
